package com.test.application.linuxState;


import com.sun.management.OperatingSystemMXBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.text.DecimalFormat;

@RestController
@Slf4j
@RequestMapping("/cpu")
public class CpuStateLinuxCommon {
    /**
     * 获取设备运行指标
     *
     * @return 指标值对象
     */
    @GetMapping("/state2")
    public RunQuotaDto runQuota() {
        RunQuotaDto runQuotaDto = new RunQuotaDto();
        try {
            // 获取CPU使用率
            getCpuInfo(runQuotaDto);
            // 获取内存信息
            getMemoryInfo1(runQuotaDto);
            // 获取磁盘总数-字节
            getDistInfo(runQuotaDto);
            //--获取当前网络吞吐量
            getNetIO(runQuotaDto);
        } catch (Exception e) {
            log.error("获取设备状态信息失败：{}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
        return runQuotaDto;
    }
    //获取CPU信息
    private void getCpuInfo(RunQuotaDto  runQuotaDto) throws IOException {
        OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        double cpuAverageUsedRatio = osBean.getSystemCpuLoad();
        cpuAverageUsedRatio = (double) Math.round(cpuAverageUsedRatio * 10000);
        log.info("CPU使用率（万分率）: {}", cpuAverageUsedRatio);
        runQuotaDto.setCpuAverageUsedRatio((int) Math.round(cpuAverageUsedRatio));
        double cpuValue = (cpuAverageUsedRatio / 100);
        log.info("CPU使用率: {}%", cpuValue);

        // 获取CPU核心数
        Process cpuProcess = Runtime.getRuntime().exec("nproc");//TODO  其他方法
        int cpuCount = 0;
        InputStream inputStream = cpuProcess.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            try {
                cpuCount = Integer.parseInt(line);
            } catch (Exception e) {
                throw new IOException(e.getMessage());
            }
            log.info("CPU核心数: {}", cpuCount);
            runQuotaDto.setCpuCoreNumber(cpuCount);
        }
    }

    //获取内存信息(方法一)
    private void getMemoryInfo1(RunQuotaDto runQuotaDto) throws Exception {
        Process process = Runtime.getRuntime().exec("free -b");// TODO 其他方法
        InputStream inputStream = process.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        DecimalFormat decimalFormat = new DecimalFormat("#.##");
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            // 解析输出数据
            if (line.startsWith("Mem:")) {
                String[] split = line.split("\\s+");
                long totalMemory = Long.parseLong(split[1]);// 总内存大小
                runQuotaDto.setMemoryTotal(totalMemory);
                log.info("内存总数: {}字节", totalMemory);
                long usedMemory = Long.parseLong(split[2]);// 已用内存大小
                runQuotaDto.setMemoryUsedCount(usedMemory);
                log.info("内存使用数: {}字节", usedMemory);
                long avaMemory = Long.parseLong(split[6]);// 可用内存大小
                double memoryUsage = (double) (totalMemory - avaMemory) / totalMemory * 100;// 计算内存使用率
                String memoryValue = decimalFormat.format(memoryUsage);
                log.info("内存使用率: {}%", memoryValue);
            }
        }
    }

    //获取网络吞吐量
    private void getNetIO(RunQuotaDto runQuotaDto) throws Exception {
        //--1 记录当前时间戳 并查询当前接收的字节数和发送的字节数
        long sumReceiveBytes = 0;//接收总字节数
        long sumSendBytes = 0;//发送总字节数
        long startTime = System.currentTimeMillis();
        log.info("开始时间: {}", startTime);
        Process process = Runtime.getRuntime().exec("cat /proc/net/dev");
        InputStream inputStream = process.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            if (line.trim().startsWith("Inter") || line.trim().startsWith("lo") || line.trim().startsWith("face")) {
                continue;
            }
            // 解析输出数据
            String[] parts = line.trim().split("\\s+");
            long rxBytesStart = Long.parseLong(parts[1]);// 接收字节数
            log.info("记录开始 -- 网卡：{} 接收字节数: {}字节", parts[0], rxBytesStart);
            sumReceiveBytes -= rxBytesStart;
            long txBytesStart = Long.parseLong(parts[9]);// 发送字节数
            log.info("记录开始 -- 网卡：{} 发送字节数: {}字节", parts[0], txBytesStart);
            sumSendBytes -= txBytesStart;
        }

        Thread.sleep(100);//数据采集时间间隔100毫秒 TODO 暂定

        //--2 再次记录当前时间戳 并查询当前接收的字节数和发送的字节数
        long endTime = System.currentTimeMillis();
        log.info("结束时间: {}", endTime);
        process = Runtime.getRuntime().exec("cat /proc/net/dev");
        inputStream = process.getInputStream();
        bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        while ((line = bufferedReader.readLine()) != null) {
            if (line.trim().startsWith("Inter") || line.trim().startsWith("lo") || line.trim().startsWith("face")) {
                continue;
            }
            // 解析输出数据
            String[] parts = line.trim().split("\\s+");
            long rxBytesEnd = Long.parseLong(parts[1]);// 接收字节数
            log.info("记录结束 -- 网卡：{} 接收字节数: {}字节", parts[0], rxBytesEnd);
            sumReceiveBytes += rxBytesEnd;
            long txBytesEnd = Long.parseLong(parts[9]);// 发送字节数
            log.info("记录结束 -- 网卡：{} 发送字节数: {}字节", parts[0], txBytesEnd);
            sumSendBytes += txBytesEnd;
        }
        //--3 运算当前吞吐量 以bps为单位
        long sumBytes = sumReceiveBytes + sumSendBytes;
        long spendTime = endTime - startTime;
        log.info("接收与发送字节数总和: {}字节", sumBytes);
        log.info("花费时间: {}毫秒", spendTime);
        double bps = sumBytes * 8 * 1000 / (double) spendTime;
        log.info("当前网络吞吐量: {}bps", bps);
        runQuotaDto.setNetworkThroughput(Math.round(bps));
        log.info("当前网络吞吐量: {}", bps);
        // 等待命令执行完成
        process.waitFor();
        bufferedReader.close();
        inputStream.close();
    }

    // 获取磁盘信息
    private void getDistInfo(RunQuotaDto  runQuotaDto) {
        if (ObjectUtils.isEmpty(runQuotaDto)) {
            return;
        }
        // 获取所有磁盘分区列表
        File[] roots = File.listRoots();
        long totalSize = 0;
        long freeSize = 0;
        long usedSize = 0;
        for (File file : roots) {
            // 获取磁盘分区的名称
            String drive = file.getAbsolutePath();
            // 获取磁盘分区的总容量
            totalSize += file.getTotalSpace();
            // 获取磁盘分区的可用空间
            freeSize += file.getFreeSpace();
            // 计算已使用的空间
            usedSize += totalSize - freeSize;
            log.info("分区: {} 总容量: {} 已使用: {} 空闲: {}", drive, formatBytes(file.getTotalSpace()), formatBytes(totalSize - freeSize), formatBytes(file.getTotalSpace()));
        }
        runQuotaDto.setDiskTotal(totalSize); //磁盘总量
        log.info("磁盘总量: {}", formatBytes(totalSize));
        runQuotaDto.setDiskUsedCount(usedSize); //磁盘已使用
        log.info("磁盘已使用: {}", formatBytes(usedSize));
        runQuotaDto.setDiskIoLoadRate(Math.round((float) (usedSize * 10000) / totalSize)); //磁盘IO负载率（万分率）
        log.info("磁盘IO负载率: {}%", runQuotaDto.getDiskIoLoadRate());
    }

    // 格式化字节大小
    private static String formatBytes(long bytes) {
        if (bytes >= 1024 * 1024 * 1024) {
            return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));
        } else if (bytes >= 1024 * 1024) {
            return String.format("%.2f MB", bytes / (1024.0 * 1024));
        } else if (bytes >= 1024) {
            return String.format("%.2f KB", bytes / 1024.0);
        } else {
            return bytes + " B";
        }
    }

}

